Platformer TutorialWriting Game Logic ModuleWriting Game Logic Module Welcome to the seventh tutorial of the Dora SSR game engine side-scrolling 2D game development series! In this tutorial, we will introduce how to use the ECS (Entity Component System) framework of Dora SSR to write game logic modules. ECS is a commonly used game development pattern that decomposes game data processing into entities, components, and systems, making the game logic clearer and the code easier to manage and extend. In Dora SSR, the ECS framework is provided by components such as Entity, Observer, and Group with their respective functionalities. First, we need to import some necessary modules. This time, we are importing several functional components, indicating that the implementation of this module will be relatively complex: Script/Logic.tllocal type Entity = require("Entity")local Observer <const> = require("Observer")local Sprite <const> = require("Sprite")local Spawn <const> = require("Spawn")local AngleY <const> = require("AngleY")local Sequence <const> = require("Sequence")local Y <const> = require("Y")local Scale <const> = require("Scale")local Opacity <const> = require("Opacity")local Ease <const> = require("Ease")local tolua <const> = require("tolua")local Platformer <const> = require("Platformer")local BodyDef <const> = require("BodyDef")local Vec2 <const> = require("Vec2")local Body <const> = require("Body")local type Dictionary = require("Dictionary")local sleep <const> = require("sleep")local once <const> = require("once")local loop <const> = require("loop")local Config <const> = require("Script.Config")local Data <const> = Platformer.Datalocal Unit <const> = Platformer.Unit Next, we create an Observer to monitor the creation behavior of the game player character entity. When an entity is created, we create a Unit object representing the actual player character scene node and perform the necessary initialization operations. Therefore, the Entity represents pure game data objects, and the rendering and interaction of game functions in the game scene rely on the creation of scene node objects corresponding to the game data: Script/Logic.tlObserver("Add", {"player"}):watch(function(self: Entity.Type): boolean local unitDef = Data.store["Unit:player"] as Dictionary.Type local world = Data.store["Scene:world"] as Platformer.PlatformWorld.Type if unitDef is nil or world is nil then return false end local unit = Unit(unitDef, world, self, Vec2(300, -350)) unit.order = Config.PlayerLayer unit.group = Config.PlayerGroup unit.playable.position = Vec2(0, -150) unit.playable:play("idle", true) world:addChild(unit) world.camera.followTarget = unit return falseend) Then, we create another Observer to monitor the creation behavior of game item entities. When an entity is created, we create a Sprite object, which represents the graphic representation of the game item. At the same time, we also create a physical body Body object for the game item and add a sensor to it. This sensor can detect collisions with other objects. When a collision with the player object is detected, it triggers a node event called "BodyEnter" and executes the registered item pickup processing logic: Script/Logic.tlObserver("Add", {"x", "icon"}):watch(function(self: Entity.Type, x: number, icon: string): boolean local world = Data.store["Scene:world"] as Platformer.PlatformWorld.Type if world is nil then return false end -- Create the display graphics and animation for the item in the scene local sprite = Sprite(icon) sprite:schedule(loop(function(): boolean sleep(sprite:runAction(Spawn( AngleY(5, 0, 360), Sequence( Y(2.5, 0, 40, Ease.OutQuad), Y(2.5, 40, 0, Ease.InQuad) ) ))) end)) -- Create the definition of the physical collision body for the item local bodyDef = BodyDef() bodyDef.type = "Dynamic" bodyDef.linearAcceleration = Vec2(0, -10) bodyDef:attachPolygon(sprite.width * 0.5, sprite.height) bodyDef:attachPolygonSensor(0, sprite.width, sprite.height) -- Create the physical body node for the item in the scene local body = Body(bodyDef, world, Vec2(x, 0)) body.order = Config.ItemLayer body.group = Config.ItemGroup body:addChild(sprite) body:slot("BodyEnter", function(item: Body.Type) if tolua.type(item) == "Platformer::Unit" then self.picked = true body.group = Data.groupHide body:schedule(once(function() sleep(sprite:runAction(Spawn( Scale(0.2, 1, 1.3, Ease.OutBack), Opacity(0.2, 1, 0) ))) self.body = nil end)) end end) world:addChild(body) -- Store the node object of the item in the scene as a component on an entity -- for triggering subsequent processing logic self.body = body return falseend) Finally, we create an Observer to monitor the deletion behavior of the body component on entities. When the body component is removed, we destroy the related game objects: Script/Logic.tlObserver("Remove", {"body"}):watch(function(self: Entity.Type): boolean (self.oldValues.body as Body.Type):removeFromParent() return falseend) With this, our game logic module is complete. In this module, we use the ECS framework of Dora SSR to monitor the creation and deletion behaviors of entities and perform corresponding logical operations based on entity changes. In the upcoming tutorials, we will continue to explore how to use the Dora SSR game engine to develop side-scrolling 2D games. We hope you can keep up with our pace and learn the usage of the Dora SSR game engine together!